package com.candoit.webapps.pricing.util.spreadsheet;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import com.candoit.webapps.pricing.model.Articulo;
import com.candoit.webapps.pricing.model.CategoriaCuenta;
import com.candoit.webapps.pricing.model.CentroCostos;
import com.candoit.webapps.pricing.model.CriterioDistribucion;
import com.candoit.webapps.pricing.model.Cuenta;
import com.candoit.webapps.pricing.model.MateriaPrima;
import com.candoit.webapps.pricing.model.TipoLinea;
import com.candoit.webapps.pricing.model.TipoMateriaPrima;

public class ReportInSpreadsheet {
	
	private static final String MP_SHEET_NAME = "Costos Materias Primas";
	private static final String BDI_SHEET_NAME = "Gastos";
	private static final String SALARY_SHEET_NAME = "Salarios";
	
	private Map<Articulo, ReportClass> reportMPOrderedByArticulo(List<Articulo> articulos, TipoLinea tipoProductivo,Boolean simulado){
		Map<Articulo, ReportClass> report = new HashMap<Articulo, ReportClass>();
		CommandMPForSpreadsheet cfs = new CommandMPForSpreadsheet(tipoProductivo);
		for(Articulo a : articulos){
			ReportClass raux = new ReportClass();
			raux.setCostos(cfs.listarValoresPorArticulo(a,simulado));
			raux.setConsumosMateriasPrimas(cfs.getConsumosMateriasPrimas());
			report.put(a, raux);
		}
		return report;
	}
	
	/*ACLARACION: El objeto HSSFWorkbook es necesario para crear el estilo y la fuente*/
	public void writeReportInSpreadsheet(HSSFWorkbook wb, List<Articulo> articulos, TipoLinea tipoProductivo,Boolean simulado){
		HSSFSheet sheet = wb.createSheet(MP_SHEET_NAME);
		
		Map<Articulo, ReportClass> report = reportMPOrderedByArticulo(articulos, tipoProductivo,simulado);
		
		for (Articulo a : articulos){
			writeArticleCost(a,sheet,report.get(a));
		}
		
	}
	
	/*ACLARACION: El objeto HSSFWorkbook es necesario para crear el estilo y la fuente*/
	public void writeReportIndustrialDistributionBases(
			HSSFWorkbook wb, 
			Map<CriterioDistribucion, Map<CentroCostos, Double>> matriz_proporcion_criterio_cc,
			Boolean simulado)
	{
		HSSFSheet sheet = wb.createSheet(BDI_SHEET_NAME);
		CommandBDIForSpreadsheet report = new CommandBDIForSpreadsheet(matriz_proporcion_criterio_cc,simulado);
		writeResportCCP(wb,report, sheet);
	}
	
	/*ACLARACION: El objeto HSSFWorkbook es necesario para crear el estilo y la fuente*/
	public void writeReportSalaries(
			HSSFWorkbook wb, 
			Map<CriterioDistribucion, Map<CentroCostos, Double>> matriz_proporcion_criterio_cc,
			Boolean simulado)
	{
		HSSFSheet sheet = wb.createSheet(SALARY_SHEET_NAME);
		CommandSalariesForSpreadsheet report = new CommandSalariesForSpreadsheet(matriz_proporcion_criterio_cc,simulado);
		writeResportSalaries(wb,report, sheet);
	}
	
	public void writeResportSalaries(HSSFWorkbook wb, CommandSalariesForSpreadsheet rep, HSSFSheet sheet ){
		HSSFRow row = sheet.createRow(0);
		Map<CentroCostos,Double> salariosCCP = rep.getSalariosCCP();
		
		Integer currentRow = sheet.getLastRowNum();
		
		row = sheet.createRow(currentRow);
		
		/*Salarios de centros de costos productivos*/
		row.createCell(1).setCellValue("TOTAL");
        Integer i = 2;
		for(CentroCostos cc : salariosCCP.keySet()){
			row.createCell(i++).setCellValue(cc.getNombre());
		}
		currentRow++;	        
	    row = sheet.createRow(currentRow);
	    i = 0;
	    row.createCell(i++).setCellValue("Salarios");
	    Double totalSalariosCC = rep.getTotalSalariosCC();
	    row.createCell(i++).setCellValue(totalSalariosCC);	    
		for(CentroCostos cc : salariosCCP.keySet()){
			row.createCell(i++).setCellValue(salariosCCP.get(cc));
		}
		
		currentRow +=2;
		
		/*Salarios de centros de costos distribuidos sobre para-productivos directos*/
		row = sheet.createRow(currentRow);
		row.createCell(0).setCellValue("PRORRATEO PARA PRODUCTIVOS");
		row.createCell(1).setCellValue("TOTAL");
		i = 2;
		for(CentroCostos cc : salariosCCP.keySet()){
			row.createCell(i++).setCellValue(cc.getNombre());
		}
		currentRow++;
		Double totalesCCPPD = 0.;
		Map<CentroCostos, Double> salariosCCPPD = rep.getSalariosCCPPD();
		for(CentroCostos ccppd : salariosCCPPD.keySet()){
			row = sheet.createRow(currentRow);
			row.createCell(0).setCellValue(ccppd.getNombre());
			Double totalCCPPD = rep.getTotalSalaryForCCPPD(ccppd);
			totalesCCPPD += totalCCPPD;
			row.createCell(1).setCellValue(round(totalCCPPD));
			i = 2;
			for(CentroCostos cc : salariosCCP.keySet()){
				Double salaryD = rep.getDistributedSalaryForCentroCostos(cc,ccppd);
				row.createCell(i++).setCellValue(round(salaryD));
			}
			currentRow++;
		}
		row = sheet.createRow(currentRow);
		row.createCell(0).setCellValue("TOTALES");
		row.createCell(1).setCellValue(round(totalesCCPPD));
		i = 2;
		for(CentroCostos cc : salariosCCP.keySet()){
			Double total = rep.getTotalDistributedSalaryForCentroCostos(cc);
			row.createCell(i++).setCellValue(round(total));
		}
		currentRow += 2;
		
		Double TotalProductivosYParaProductivos = totalSalariosCC + totalesCCPPD;
		row = sheet.createRow(currentRow);
		row.createCell(0).setCellValue("PRODUCTIVOS + PARA PRODUCTIVOS");
		row.createCell(1).setCellValue(round(TotalProductivosYParaProductivos));
		i = 2;
		Map<CentroCostos,Double> pypp = rep.getsalariosProductivosYParaProductivos();
		for(CentroCostos cc : salariosCCP.keySet()){
			Double total = pypp.get(cc);
			row.createCell(i++).setCellValue(round(total));
		}
		
	}
	
	public void writeResportCCP(HSSFWorkbook wb, CommandBDIForSpreadsheet rep, HSSFSheet sheet ){
		HSSFRow row = sheet.createRow(0);
		Map<CategoriaCuenta,Map<Cuenta,Double>> categoriasMap = rep.getCategoriasMap();
		List<CentroCostos> centros = rep.getCentros();
		
		Integer currentRow = sheet.getLastRowNum();
		Integer padding_bottom = 1;
		
		/*inicializo el mapa de los subtotales*/
        Map<CentroCostos,Double> totales = new HashMap<CentroCostos,Double>();
        for(CentroCostos cc : centros){
        	totales.put(cc, 0.0);
        }
        Double total = 0.0;
		
		for(CategoriaCuenta ca : categoriasMap.keySet()){
			/*headers*/
			row = sheet.createRow(currentRow);
	        row.createCell(0).setCellValue(ca.getDescripcion());
	        row.createCell(1).setCellValue("TOTAL");
	        Integer i = 2;
	        for(CentroCostos cc : centros){
	        	row.createCell(i++).setCellValue(cc.getNombre());
	        }
	        
	        /*inicializo el mapa de los subtotales*/
	        Map<CentroCostos,Double> subTotales = new HashMap<CentroCostos,Double>();
	        for(CentroCostos cc : centros){
	        	subTotales.put(cc, 0.0);
	        }
	        Double subtotal = 0.0;
	        
	        /*escribo los valores de las cuentas de esa categoria para cada centro de costo*/
	        for(Cuenta cu : categoriasMap.get(ca).keySet()){
	        	/*salto de linea*/
		        currentRow++;	        
		        row = sheet.createRow(currentRow);
		        row.createCell(0).setCellValue(cu.getDescripcion());
		        row.createCell(1).setCellValue(round(categoriasMap.get(ca).get(cu)));
		        subtotal += categoriasMap.get(ca).get(cu);
		        i = 2;
		        for(CentroCostos cc : centros){
		        	row.createCell(i++).setCellValue(round(rep.getCost(cu,cc)));
		        	subTotales.put(cc, subTotales.get(cc)+rep.getCost(cu,cc));
		        }
	        }
	        /*escribo subtotales*/
	        /*salto de linea*/
	        currentRow++;	        
	        row = sheet.createRow(currentRow);
	        row.createCell(0).setCellValue("SUBTOTALES");
	        row.createCell(1).setCellValue(round(subtotal));
	        i = 2;
	        for(CentroCostos cc : centros){
	        	row.createCell(i++).setCellValue(round(subTotales.get(cc)));
	        	totales.put(cc, totales.get(cc)+subTotales.get(cc));
	        }
	        total += subtotal;
	        
	        /*salto de linea*/
	        currentRow++;
	        
	        /*aplico padding_bottom*/
	        currentRow += padding_bottom;
		}
        /*escribo totales*/	        
        row = sheet.createRow(currentRow);
        row.createCell(0).setCellValue("TOTAL APERTURA");
        row.createCell(1).setCellValue(round(total));
        Integer i = 2;
        for(CentroCostos cc : centros){
        	row.createCell(i++).setCellValue(round(totales.get(cc)));
        }

		
		currentRow += 3;
		/*headers*/
		row = sheet.createRow(currentRow);
        row.createCell(0).setCellValue("PRORRATEO PARA PRODUCTIVOS");
        row.createCell(1).setCellValue("TOTAL");
        i = 2;
        for(CentroCostos maquina : centros){
        	row.createCell(i++).setCellValue(maquina.getNombre());
        }
		
        
        /*inicializo el mapa de los totales ccppd*/
        Map<CentroCostos,Double> totalesCCPPD = new HashMap<CentroCostos,Double>();
        for(CentroCostos cc : centros){
        	totalesCCPPD.put(cc, 0.0);
        }
        Double totalCCPPD = 0.0;
		for(CentroCostos cc : rep.getTotalesProrrateoPP().keySet()){
			/*salto de linea*/
	        currentRow++;	        
	        row = sheet.createRow(currentRow);
	        row.createCell(0).setCellValue(cc.getNombre());
	        row.createCell(1).setCellValue(round(rep.getTotalesProrrateoPP().get(cc)));
	        totalCCPPD += rep.getTotalesProrrateoPP().get(cc);
	        i = 2;
	        for(CentroCostos maquina : centros){
	        	row.createCell(i++).setCellValue(round(rep.getCcppdCosto().get(cc).get(maquina)));
	        	totalesCCPPD.put(maquina, totalesCCPPD.get(maquina) + rep.getCcppdCosto().get(cc).get(maquina));
	        }
		}
		/*escribo totales CCPPD*/
        /*salto de linea*/
        currentRow++;	        
        row = sheet.createRow(currentRow);
        row.createCell(0).setCellValue("TOTALES REASIGNADOS");
        row.createCell(1).setCellValue(totalCCPPD);
        i = 2;
        for(CentroCostos cc : centros){
        	row.createCell(i++).setCellValue(round(totalesCCPPD.get(cc)));
        }

        /*escribo totales PRODUCTIVOS + PARA PRODUCTIVOS*/
        /*salto de linea X 2*/
        currentRow += 2;	        
        row = sheet.createRow(currentRow);
        row.createCell(0).setCellValue("PRODUCTIVOS + PARA PRODUCTIVOS");
        row.createCell(1).setCellValue(round(total + totalCCPPD));
        i = 2;
        for(CentroCostos cc : centros){
        	row.createCell(i++).setCellValue(round(totales.get(cc)+totalesCCPPD.get(cc)));
        }

        
	}
	
	public static double round(double d){
		int decimalPlace = 2;
	    BigDecimal bd = new BigDecimal(Double.toString(d));
	    bd = bd.setScale(decimalPlace,BigDecimal.ROUND_HALF_UP);
	    return bd.doubleValue();
	  }
	
	private void writeArticleCost(Articulo articulo, HSSFSheet sheet, ReportClass report){
		Integer padding_top = 2;
		
		HSSFRow row;  
		
		/*escribir articulo*/
		Integer currentRow = sheet.getLastRowNum() + padding_top;
        row = sheet.createRow(currentRow);
        row.createCell(0).setCellValue(articulo.getDescripcion());
        
        /*escribo papeles*/
        Integer i=3;
        for (MateriaPrima mp : report.getCostos().keySet()){
        	row.createCell(i).setCellValue(mp.getNombre());
        	i++;
        }
        
        /*escribir segunda fila*/
        row = sheet.createRow(++currentRow);
        row.createCell(1).setCellValue("DESCRIPCION");
        row.createCell(2).setCellValue("CONSUMOS");
        i=3;
        for (MateriaPrima mp : report.getCostos().keySet()){
        	if(mp.getGramaje() == null){
        		mp.setGramaje(0.0);
        	}
        	row.createCell(i).setCellValue(mp.getGramaje());
        	i++;
        }
        
        Integer bRow = currentRow + 1;
        /*Escribo los costos de cada materia prima, fila por fila*/
        for (TipoMateriaPrima tmp : report.getConsumosMateriasPrimas().keySet()){
        	Integer bCol = 1;
        	/*escribe nombre y despues el consumo del tipo de materia prima*/
        	row = sheet.createRow(bRow);
        	row.createCell(bCol++).setCellValue(tmp.getDescripcion());
        	row.createCell(bCol++).setCellValue(report.getConsumosMateriasPrimas().get(tmp));
        	
        	for( MateriaPrima mp : report.getCostos().keySet() ){
        		try {
        			row.createCell(bCol++).setCellValue(report.getCostos().get(mp).getCost(tmp));
					
				} catch (Exception e) {
					e.printStackTrace();
				}
        	}
        	bRow++;
        }
        
        /*Desperdicio*/
        Integer bCol = 1;
    	row = sheet.createRow(bRow);
    	row.createCell(bCol++).setCellValue("Desperdicio");
    	bCol++;
    	for( MateriaPrima mp : report.getCostos().keySet() ){
    		row.createCell(bCol++).setCellValue(report.getCostos().get(mp).getScrap());
    	}
    	bRow++;
    	
    	/*Total*/
        bCol = 1;
    	row = sheet.createRow(bRow);
    	row.createCell(bCol++).setCellValue("Total");
    	bCol++;
    	for( MateriaPrima mp : report.getCostos().keySet() ){
    		row.createCell(bCol++).setCellValue(report.getCostos().get(mp).getTotal());
    	}
    	bRow++;
    	
	}
	
	private Double g(MateriaPrima i, TipoMateriaPrima j, Map<MateriaPrima, CommandMPCostsDetails> report){
		return report.get(i).getCost(j);
	}
	
	private class ReportClass{
		private Map<MateriaPrima, CommandMPCostsDetails> costos;
		private Map<TipoMateriaPrima,Double> consumosMateriasPrimas;
		
		public Map<MateriaPrima, CommandMPCostsDetails> getCostos() {
			return costos;
		}
		public void setCostos(Map<MateriaPrima, CommandMPCostsDetails> costos) {
			this.costos = costos;
		}
		public Map<TipoMateriaPrima, Double> getConsumosMateriasPrimas() {
			return consumosMateriasPrimas;
		}
		public void setConsumosMateriasPrimas(
				Map<TipoMateriaPrima, Double> consumosMateriasPrimas) {
			this.consumosMateriasPrimas = consumosMateriasPrimas;
		}
		
	}
}
